#!/usr/bin/env python2.5

from mock import Mock, MockMethod, ReturnValue
import mock
import unittest

class MockTestCase(unittest.TestCase):
    def test_mock_without_expectations_should_verify(self):
        mock = Mock(self)
        mock.verify()

    def test_mock_should_verify_when_method_is_called_as_expected_without_args(self):
        mock = Mock(self)
        mock.expect('some_method')
        mock.some_method()
        mock.verify()

    def test_mock_should_verify_when_method_is_called_with_correct_args(self):
        mock = Mock(self)
        mock.expect('some_method', 12, 24)
        mock.some_method(12, 24)
        mock.verify()
        
    def test_mock_should_not_verify_when_method_is_called_with_no_args_when_args_expected(self):
        mock = Mock(self)
        mock.expect('some_method', 'o', 'p')
        verified = True
        try: 
            mock.some_method()
        except self.failureException:
            verified = False
        self.assertFalse(verified)
        
    def test_mock_should_not_verify_when_method_is_called_with_args_when_no_args_expected(self):
        mock = Mock(self)
        mock.expect('some_method')
        verified = True
        try: 
            mock.some_method('o', 'p')
        except self.failureException:
            verified = False
        self.assertFalse(verified)
        
    def test_mock_should_not_verify_when_method_was_not_called(self):
        mock = Mock(self)
        mock.expect('some_method')
        verified = True
        try: 
            mock.verify()
        except self.failureException:
            verified = False
        self.assertFalse(verified)
        
    def test_mock_should_return_the_specified_value_when_expected_method_is_called(self):
        mock = Mock(self)
        mock.expect('method').returns('value')
        self.assertEqual('value', mock.method())
        mock = Mock(self)
        mock.expect('method', 'arg1', 'arg2').returns('anotherValue')
        self.assertEqual('anotherValue', mock.method('arg1', 'arg2'))
        
    def test_mock_should_verify_when_multiple_calls_occur_in_the_correct_order(self):
        mock = Mock(self)
        mock.expect('method_one')
        mock.expect('method_two', 2).returns(1)
        mock.method_one()
        verified = True
        try: 
            mock.verify() # 1st expectation has been met but not 2nd - should fail
        except self.failureException:
            verified = False
        self.assertFalse(verified)
        
        self.assertEqual(1, mock.method_two(2))
        try: 
            mock.verify() # 2nd expectation is now met - should succeed
            verified = True
        except self.failureException:
            verified = False
        self.assertTrue(verified)
        
    def test_mock_should_not_verify_when_multiple_calls_occur_in_incorrect_order(self):
        mock = Mock(self)
        mock.expect('method_one')
        mock.expect('method_two', 2).returns(1)
        verified = True
        try: 
            mock.method_two(2) # 1st expectation has not been met yet - should fail
        except self.failureException:
            verified = False
        self.assertFalse(verified)
        
    def test_mock_should_not_verify_when_incorrect_number_of_calls_received(self):
        mock = Mock(self)
        mock.expect('repeated_method').twice()
        mock.repeated_method() 
        verified = True
        try:
            mock.verify() 
        except self.failureException:
            verified = False
        self.assertFalse(verified)
        
    def test_mock_should_return_attributes_that_have_been_set(self):
        mock = Mock(self)
        mock.some_value = 3
        self.assertEqual(3, mock.some_value)
        self.assertEqual(3, getattr(mock, 'some_value'))
    
class MockMethodTestCase(unittest.TestCase):
    def test_uncalled_mock_method_should_not_verify(self):
        mock_method = MockMethod(self, 'name')
        verified = True
        try:
            mock_method.verify()
        except self.failureException:
            verified = False
        self.assertFalse(verified)
        
    def test_called_mock_method_should_verify(self):
        mock_method = MockMethod(self, 'name')
        mock_method()
        mock_method.verify()
        
    def test_mock_method_should_verify_with_correct_args(self):
        mock_method = MockMethod(self, 'name')
        mock_method.expect(1, 2)
        mock_method(1, 2)
        mock_method.verify()
        
    def test_mock_method_should_not_verify_with_incorrect_args(self):
        mock_method = MockMethod(self, 'name')
        mock_method.expect(1, 2)
        try:
            mock_method(2, 1)
        except self.failureException:
            pass # expected
        mock_method.verify()
    
    def test_mock_method_expecting_noargs_should_not_verify_with_args(self):
        mock_method = MockMethod(self, 'name')
        mock_method.expect_noargs()
        try:
            mock_method(3, 4)
        except self.failureException:
            pass # expected
        mock_method.verify()
        
    def test_mock_method_should_not_verify_by_default_when_called_twice(self):
        mock_method = MockMethod(self, 'name')
        mock_method() #ok 1st time
        verified = True
        try:
            mock_method() # not ok 2nd time
        except self.failureException:
            verified = False
        self.assertFalse(verified)

    def test_mock_method_should_verify_when_called_twice_if_expected(self):
        mock_method = MockMethod(self, 'name')
        mock_method.expect_noargs().twice()
        mock_method() 
        mock_method() 
        mock_method.verify() 
    
    def test_mock_method_should_not_verify_when_expected_two_calls_but_one_made(self):
        mock_method = MockMethod(self, 'name')
        mock_method.expect_noargs().twice()
        mock_method() 
        verified = True
        try:
            mock_method.verify() 
        except self.failureException:
            verified = False
        self.assertFalse(verified)

class SuperDuperException(Exception):
    pass

class ReturnValueTestCase(unittest.TestCase):     
    def setUp(self):   
        self.mock_method = MockMethod(self, 'name')
        
    def test_return_value_should_be_None_by_default(self):
        value = ReturnValue(self.mock_method)
        self.assertEqual(None, value())
        
    def test_return_value_should_be_set_by_returns_method(self):
        value = ReturnValue(self.mock_method)
        value.returns(3)
        self.assertEqual(3, value())
        
    def test_return_value_should_raise_exception_when_primed(self):
        value = ReturnValue(self.mock_method)
        value.raises(SuperDuperException())
        try:
            value()
            self.fail('Expected exception!')
        except SuperDuperException:
            pass # expected
        
    def test_return_value_should_pass_repeated_execution_times_to_owning_mock_method(self):
        value = ReturnValue(self.mock_method)
        value.times(2)
        self.assertEqual(2, self.mock_method.calls_remaining)

if __name__ == '__main__':
    reload(mock)
    try: unittest.main()
    except SystemExit: pass